package network;

import java.net.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.io.*;

//** Classe associee a chaque client **/
//** Il y aura autant d'instances de cette classe que de clients connectes **/
public class KrakenThread implements Runnable {
	
	private Thread thread;
	private Socket socket;
	private PrintWriter out; // pour gestion du flux de sortie
	private BufferedReader in; // pour gestion du flux d'entree
	private KrakenServer krakenServer;
	private int numClient = 0;
	private KrakenCommandInterpreter rci;
	private boolean run;
	
	final Lock lock = new ReentrantLock();
	final Condition turn = lock.newCondition();

	//** Constructeur : cree les elements necessaires au dialogue avec le client **.
	public KrakenThread(Socket s, KrakenServer krakenServer){
		this.krakenServer = krakenServer;
		socket = s;
		rci = null;
		run = true;
		try{
			// fabrication d'une variable permettant l'utilisation du flux de sortie avec des string
			out = new PrintWriter(socket.getOutputStream());
			// fabrication d'une variable permettant l'utilisation du flux d'entree avec des string
			in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			// ajoute le flux de sortie dans la liste et recuperation de son numero
			numClient = krakenServer.addClient(out);
		}
		catch(IOException e){
			e.printStackTrace(); //
		}
	
		thread = new Thread(this);
		thread.start();
	}

	//** Methode :  executee au lancement du thread par thread.start() **/
	//** Elle attend les messages en provenance du serveur et les redirige **/
	public synchronized void run(){
		String message = "";
		// on indique dans la console la connection d'un nouveau client
		System.out.println("Un nouveau client s'est connecte, no " + numClient);
		rci = new KrakenCommandInterpreter(this);
		try{
			while(run){
				message = in.readLine();
				if(!message.equalsIgnoreCase("")){
					if(rci != null)	rci.interpret(message);
					message = "";
				}
			}
		}
		catch(Exception e) {
			System.out.println("exiting thread");
		}
		
		finally{ // finally se produira le plus souvent lors de la deconnexion du client
			//System.out.println("Le client no " + numClient + " s'est deconnecte");
			//krakenServer.delClient(numClient);
			try{
				System.out.println("Le client no " + numClient + " s'est deconnecte");
				krakenServer.delClient(numClient); 
				socket.close();
			}
			catch(IOException e){
				e.printStackTrace(); //
			}
		}
	}
	
	public void setRogueCommandInterpreter(KrakenCommandInterpreter rci){
		this.rci = rci;
	}
	
	public KrakenServer getKrakenServer() { return this.krakenServer; }
	
	public void sendCommand(String cmd){
		out.println(cmd);
		out.flush();
		//System.out.println("Sended to client "+cmd);
	}

	public Socket getSocket() {
		return socket;
	}

	public void setSocket(Socket socket) {
		this.socket = socket;
	}
	
	public boolean getRunState(){ return this.run;	}
	public void setRunOff(){ this.run = false;	}

	public BufferedReader getIn() { return in; }
	public void setIn(BufferedReader in) { this.in = in; }
	
}